// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TraceBrokeredMessage.cs" company="AzureContrib (Open source library http://azurecontrib.codeplex.com)">
//   Microsoft Public License (Ms-PL)
// </copyright>
// <summary>
//   Exception for errors when handling Windows Azure Cloud Drives.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Diagnostics;

using AzureContrib.WindowsAzure.ServiceRuntime;

using Microsoft.ServiceBus.Messaging;

namespace AzureContrib.WindowsAzure.Diagnostics
{
	/// <summary>
	/// A <see cref="BrokeredMessage"/> to trace to a given <see cref="Category"/> for a given <see cref="Switch"/>
	/// </summary>
	public class TraceBrokeredMessage
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="TraceBrokeredMessage"/> class. 
		/// Inititated from the data passed in.
		/// </summary>
		/// <param name="traceType">The type of trace. <seealso cref="TraceType"/></param>
		/// <param name="traceMessage"> The <see cref="TraceMessage"/> being traced.</param>
		/// <param name="roleName">The name of the role doing the tracing. <seealso cref="IRole.Name"/></param>
		/// <param name="instanceId">The id of the current instance tracing. <see cref="IRoleInstance.Id"/></param>
		/// <param name="deploymentId">The id of the current Windows Azure deployment. <seealso cref="IRoleEnvironment.DeploymentId"/></param>
		public TraceBrokeredMessage(TraceType traceType, TraceMessage traceMessage, string roleName, string instanceId, string deploymentId)
		{
			TraceType = traceType;
			Category = traceMessage.Category;
			Switch = traceMessage.Switch;
			Message = traceMessage.Message;
			RoleName = roleName;
			InstanceId = instanceId;
			DeploymentId = deploymentId;
		}

		/// <summary>
		/// Gets or sets the <see cref="TraceType"/>
		/// </summary>
		public TraceType TraceType { get; set; }

		/// <summary>
		/// Gets or sets the <see cref="Category"/> for this trace message.
		/// </summary>
		public string Category { get; set; }

		/// <summary>
		/// Gets or sets the identifying switch we trace from.
		/// </summary>
		public string Switch { get; set; }

		/// <summary>
		/// Gets or sets the message traced.
		/// </summary>
		public string Message { get; set; }

		/// <summary>
		/// Gets or sets the unique name of the role we're sending messages from.
		/// </summary>
		public string RoleName { get; set; }

		/// <summary>
		/// Gets or sets the unique instance of the role we're sending messages from.
		/// </summary>
		public string InstanceId { get; set; }

		/// <summary>
		/// Gets or sets the unique deployment Id sending messages from.
		/// </summary>
		public string DeploymentId { get; set; }

		/// <summary>
		/// Turn a <see cref="TraceBrokeredMessage"/> into a <see cref="BrokeredMessage"/>.
		/// </summary>
		/// <param name="brokeredMessage">The <see cref="TraceBrokeredMessage"/> to convert.</param>
		/// <returns>A <see cref="BrokeredMessage"/> created from the incomming <paramref name="brokeredMessage"/>.</returns>
		public static implicit operator TraceBrokeredMessage(BrokeredMessage brokeredMessage)
		{
			TraceType traceType =
				(TraceType)Enum.Parse(typeof(TraceType), brokeredMessage.Properties[ServiceBusMessagingNames.TraceType].ToString());

			TraceLevel traceLevel =
				(TraceLevel)
				Enum.Parse(typeof(TraceLevel), brokeredMessage.Properties[ServiceBusMessagingNames.TraceLevel].ToString());
			string @switch = brokeredMessage.Properties[ServiceBusMessagingNames.Switch].ToString();
			string message = brokeredMessage.GetBody<string>();
			TraceMessage traceMessage = new TraceMessage(traceLevel, @switch, message);

			string roleName = brokeredMessage.Properties[ServiceBusMessagingNames.RoleName].ToString();
			string instanceId = brokeredMessage.Properties[ServiceBusMessagingNames.InstanceId].ToString();
			string deploymentId = brokeredMessage.Properties[ServiceBusMessagingNames.DeploymentId].ToString();

			return new TraceBrokeredMessage(traceType, traceMessage, roleName, instanceId, deploymentId);
		}

		/// <summary>
		/// Turn a <see cref="TraceBrokeredMessage"/> into a <see cref="BrokeredMessage"/>.
		/// </summary>
		/// <param name="traceBrokeredMessage">The <see cref="TraceBrokeredMessage"/> to convert.</param>
		/// <returns>A <see cref="BrokeredMessage"/> created from the incomming <paramref name="traceBrokeredMessage"/>.</returns>
		public static implicit operator BrokeredMessage(TraceBrokeredMessage traceBrokeredMessage)
		{
			var brokeredMessage = BrokeredMessage.CreateMessage(traceBrokeredMessage.Message);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.TraceType, traceBrokeredMessage.TraceType);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.TraceLevel, traceBrokeredMessage.Category);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.Switch, traceBrokeredMessage.Switch);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.RoleName, traceBrokeredMessage.RoleName);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.InstanceId, traceBrokeredMessage.InstanceId);
			brokeredMessage.Properties.Add(ServiceBusMessagingNames.DeploymentId, traceBrokeredMessage.DeploymentId);
			return brokeredMessage;
		}

		/// <summary>
		/// The names used as keys <see cref="BrokeredMessage.Properties"/>.
		/// </summary>
		public static class ServiceBusMessagingNames
		{
			/// <summary>
			/// The name of the <see cref="TraceType"/> to use in messages.
			/// </summary>
			public const string TraceType = "TraceType";

			/// <summary>
			/// The name of the <see cref="TraceLevel"/> key.
			/// </summary>
			public const string TraceLevel = "TraceLevel";

			/// <summary>
			/// A <see cref="string"/> used for a tracer switch name.
			/// </summary>
			public const string Switch = "Switch";

			/// <summary>
			/// The name of the <see cref="IRole.Name"/> key.
			/// </summary>
			public const string RoleName = "Role.Name";

			/// <summary>
			/// The name of the <see cref="IRoleInstance.Id"/> key.
			/// </summary>
			public const string InstanceId = "RoleInstance.Id";

			/// <summary>
			/// The name of the <see cref="IRoleEnvironment.DeploymentId"/> key.
			/// </summary>
			public const string DeploymentId = "RoleEnvironment.DeploymentId";
		}
	}
}